"""
文件 | 数据层
"""

from gridfs import (
    GridFS,
    GridOutCursor,
)
from gridfs.synchronous.grid_file import GridOut

from db.mongodb_db.client import mongo_db
from models.po import (
    FileGridPO,
    FilePO,
)
from my_typing import *
from service.base import ServiceBase
from utils.data_utils.special import ObjectIdStr


class FileService(ServiceBase[FilePO]):
    """ 文件 | 数据层 """

    po = FilePO
    collection_name = "common_file"
    single_field_index = [
        "id",
        "user_id",
        "raw_filename",
        "filename",
        "remark",
    ]

    @classmethod
    def get_one_by_filename(
        cls,
        filename: str,
        user_id: ObjectIdStr | None = None,
        file_id: ObjectIdStr | None = None
    ) -> FilePO | None:
        if not filename:
            return None

        query = {"filename": filename}

        if user_id:
            query["user_id"] = user_id

        if file_id:
            query["id"] = file_id

        return cls.find_one(query)

    @classmethod
    def get_one_by_remark(cls, remark: str) -> FilePO | None:
        if not remark:
            return None

        return cls.find_one({"remark": remark})


class FileGridService:
    """
    文件存储 | 数据层

    不支持多文档事务！！！
    """

    po = FileGridPO
    fs: GridFS = GridFS(mongo_db, FileService.collection_name)

    @classmethod
    def get_many_by_id_list(cls, file_id_list: Iterable[ObjectIdStr]) -> Iterator[FileGridPO]:
        if not file_id_list:
            yield from ()  # 返回空生成器，类型是 Iterator[FileGridPO]

        query = {
            "id": {
                "$in": file_id_list,
            },
        }
        grid_fs_cursor: GridOutCursor = cls.fs.find(query)

        for grid_fs in grid_fs_cursor:
            yield cls.po(
                id=grid_fs.id,  # noqa: ignore[protected member]
                content=grid_fs.read(),
            )

    @classmethod
    def get_one_by_id(cls, file_id: ObjectIdStr | None) -> FileGridPO | None:
        if not file_id:
            return None

        grid_fs: GridOut | None = cls.fs.find_one({"id": file_id})

        if grid_fs is None:
            return None

        return cls.po(
            id=file_id,
            content=grid_fs.read(),
        )

    @classmethod
    def insert_one(cls, po: FileGridPO) -> None:
        cls.fs.put(po.content, _id=po.id.oid, id=po.id)
